/*
 *  +----------------------------------------------------------------------
 *  | sophon [ A FAST GAME FRAMEWORK ]
 *  +----------------------------------------------------------------------
 *  | Copyright (c) 2023-2029 All rights reserved.
 *  +----------------------------------------------------------------------
 *  | Licensed ( http:www.apache.org/licenses/LICENSE-2.0 )
 *  +----------------------------------------------------------------------
 *  | Author: jqiris <1920624985@qq.com>
 *  +----------------------------------------------------------------------
 */

use crate::treaty::*;

#[derive(PartialEq, PartialOrd, Eq, Clone, Debug, Copy)]
pub enum MaintainType {
    MaintainTypeAll = 0,
    MaintainTypeFalse = 1,
    MaintainTypeTrue = 2,
}

pub struct Filter {
    maintain_type: MaintainType,
    version: i64,
}

impl Filter {
    pub fn new(options: Option<Vec<FilterOption>>) -> Self {
        let mut filter = Filter {
            maintain_type: MaintainType::MaintainTypeFalse,
            version: 0,
        };
        if let Some(mut ops) = options {
            for op in ops.iter_mut() {
                op(&mut filter);
            }
        }
        filter
    }
    pub fn apply(&self, s: &Server) -> bool {
        if self.maintain_type > MaintainType::MaintainTypeAll {
            if let Some(maintained) = s.maintained {
                if self.maintain_type == MaintainType::MaintainTypeFalse && maintained {
                    return false;
                }
                if self.maintain_type == MaintainType::MaintainTypeTrue && !maintained {
                    return false;
                }
            } else if self.maintain_type == MaintainType::MaintainTypeTrue {
                return false;
            }
        }
        if self.version > 0 && self.version != s.version {
            return false;
        }
        return true;
    }
}

pub type FilterOption = Box<dyn FnMut(&mut Filter) + Send + Sync>;

pub fn filter_maintained(maintain_type: MaintainType) -> FilterOption {
    Box::new(move |f: &mut Filter| {
        f.maintain_type = maintain_type;
    })
}

pub fn filter_version(version: i64) -> FilterOption {
    Box::new(move |f: &mut Filter| {
        f.version = version;
    })
}
